package com.basic.library.utils.download;

import android.app.Application;
import android.os.Environment;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.basic.library.utils.FileUtils;
import com.liulishuo.okdownload.DownloadContext;
import com.liulishuo.okdownload.DownloadContextListener;
import com.liulishuo.okdownload.DownloadTask;
import com.liulishuo.okdownload.OkDownload;
import com.liulishuo.okdownload.StatusUtil;
import com.liulishuo.okdownload.core.cause.EndCause;
import com.liulishuo.okdownload.core.dispatcher.DownloadDispatcher;

import java.io.File;
import java.util.List;

/**
 * @author yj
 * @description
 */
public class Downloader {
    public String filePath = FileUtils.getFilePath() + "/" + Environment.DIRECTORY_DOWNLOADS; //文件缓存路径
    public static String tmpPath = FileUtils.getCachePath() + "/cache"; //视频自带缓存路径

    static final Downloader DOWNLOADER = new Downloader();

    public static Downloader newInstance() {
        return new Downloader();
    }

    public static Downloader getInstance() {
        return DOWNLOADER;
    }

    /**
     * 清理视频播放器自带的缓存
     */
    public void clearCacheOfVideo() {
        try {
            FileUtils.delFile(new File(tmpPath));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void init(Application context) {
        //下载器
//        OkDownload.with().setMonitor(monitor);
        DownloadDispatcher.setMaxParallelRunningCount(3); //最大并行下载数
//        RemitStoreOnSQLite.setRemitToDBDelayMillis(3000);
//        OkDownload.with().downloadDispatcher().cancelAll();
//        OkDownload.with().breakpointStore().remove(taskId);
    }

    /**
     * 本地是否有文件存在，并比较文件大小是否一致
     *
     * @param url
     * @return
     */
    public boolean downedFileExists(String url) {
        try {
            if (!TextUtils.isEmpty(url)) {
                File file = new File(getDownedFilePath(url));
                long localSize = FileUtils.getFileSize(file);
                long remoteSize = FileUtils.getRemoteFileSize(url);
                return file.exists() && remoteSize == localSize;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public String getDownedFilePath(String url) {
        return filePath + "/" + getFileName(url); //本地
    }

    /**
     * @param path
     * @return
     */
    public static String getFileName(String path) {
        try {
            if (path.contains("?"))
                path = path.substring(0, path.lastIndexOf("?"));
//            return path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
            return path.substring(path.lastIndexOf("/") + 1);
        } catch (Exception e) {
//            e.printStackTrace();
        }
        return path.substring(path.lastIndexOf("/") + 1);
    }

    /**
     * 有后缀
     *
     * @param path
     * @return
     */
    public static String getFileNameHas(String path) {
        return path.substring(path.lastIndexOf("/") + 1);
    }

    public void downQueueFile(List<String> urls, DownLoadCallBack callback) {
        DownloadContext.Builder builder = new DownloadContext.QueueSet()
                .setParentPathFile(new File(filePath))
                .setMinIntervalMillisCallbackProcess(150)
                .commit();
        for (int i = 0; i < urls.size(); i++) {
//            builder.bind(url1);
//            builder.bind(url2).addTag(key, value);
//            builder.bind(url3).setTag(tag);
            builder.setListener(contextListener);
            builder.bindSetTask(getTask(urls.get(i)));
        }

        DownloadContext context = builder.build();
        context.startOnParallel(new MDownloadListener4WithSpeed(callback)); //开始
//        context.stop(); //停止
    }

    public void downSingleFile(DownLoadCallBack callback, String url) {
        getTask(url).enqueue(new MDownloadListener4WithSpeed(callback));//异步执行任务
    }

    public void downSingleFile(DownLoadCallBack callback, DownloadTask task) {
        task.enqueue(new MDownloadListener4WithSpeed(callback));//异步执行任务
//        task.cancel();// 取消任务
//        task.execute(listener);// 同步执行任务
//        DownloadTask.enqueue(tasks, listener); //同时异步执行多个任务
    }

    public DownloadTask getTask(String url) {
        return new DownloadTask.Builder(url, new File(filePath)) //设置下载地址和下载目录，这两个是必须的参数
                .setFilename(getFileName(url))//设置下载文件名，没提供的话先看 response header ，再看 url path(即启用下面那项配置)
                .setFilenameFromResponse(false)//是否使用 response header or url path 作为文件名，此时会忽略指定的文件名，默认false
                .setPassIfAlreadyCompleted(true)//如果文件已经下载完成，再次下载时，是否忽略下载，默认为true(忽略)，设为false会从头下载
                .setConnectionCount(1)  //需要用几个线程来下载文件，默认根据文件大小确定；如果文件已经 split block，则设置后无效
                .setPreAllocateLength(false) //在获取资源长度后，设置是否需要为文件预分配长度，默认false
                .setMinIntervalMillisCallbackProcess(100) //通知调用者的频率，避免anr，默认3000
                .setWifiRequired(false)//是否只允许wifi下载，默认为false
                .setAutoCallbackToUIThread(true) //是否在主线程通知调用者，默认为true
                //.setHeaderMapFields(new HashMap<String, List<String>>())//设置请求头
                //.addHeader(String key, String value)//追加请求头
                .setPriority(0)//设置优先级，默认值是0，值越大下载优先级越高
                .setReadBufferSize(4096)//设置读取缓存区大小，默认4096
                .setFlushBufferSize(16384)//设置写入缓存区大小，默认16384
                .setSyncBufferSize(65536)//写入到文件的缓冲区大小，默认65536
                .setSyncBufferIntervalMillis(2000) //写入文件的最小时间间隔，默认2000
                .build();
    }

    public StatusUtil.Status getStatus(String url) {
        StatusUtil.Status status;
        if (downedFileExists(url)) {
            status = StatusUtil.Status.COMPLETED;
        } else {
            DownloadTask task = getTask(url);
            if (StatusUtil.isCompleted(task)) {
                status = StatusUtil.Status.COMPLETED;
            } else {
                status = StatusUtil.getStatus(task);
            }
        }
        return status;
    }

    public boolean isSuccess(String url) {
        if (downedFileExists(url)) {
            return true;
        } else {
            DownloadTask task = getTask(url);
            return StatusUtil.isCompleted(task);
        }
    }

    /**
     * 下载库自带的StatusUtil.Status.COMPLETED（本地有同名字的文件存在就是COMPLETED）
     * 导致文件缺损或掉包也是认为成功的，
     * downedFileExists进一步判断了文件大小的一致性（耗时间）
     * 综上一般还是用自带的StatusUtil.Status.COMPLETED判断就行
     *
     * @param task
     * @return
     */
    public boolean isSuccess(DownloadTask task) {
        if (task == null) return false;
        if (downedFileExists(task.getUrl())) { //先自己检查本地是否有文件
            return true;
        } else {
            return StatusUtil.isCompleted(task); //再通过第三方工具检查任务状态
        }
    }

    public void pauseAll() {
        OkDownload.with().downloadDispatcher().cancelAll();
    }

    public void pause(DownloadTask task) {
        if (task != null)
            task.cancel();
    }

    public void createFolder(String path) {
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    final DownloadContextListener contextListener = new DownloadContextListener() {
        @Override
        public void taskEnd(@NonNull DownloadContext context, @NonNull DownloadTask task, @NonNull EndCause cause, @Nullable Exception realCause, int remainCount) {

        }

        @Override
        public void queueEnd(@NonNull DownloadContext context) {

        }
    };
}
